﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Animation;

namespace BasicLight.Unleashed
{
    public class MagicButton : Button
    {
        public MagicButton()
        {
            Store = new Dictionary<string, object>();
        }

        private static readonly TimeSpan TiltReturnAnimationDuration = TimeSpan.FromMilliseconds(100);
        private static readonly TimeSpan TiltReturnAnimationDelay = TimeSpan.FromMilliseconds(200);

        private static Storyboard _tiltReturnStoryboard;
        private static DoubleAnimation _tiltReturnXAnimation;
        private static DoubleAnimation _tiltReturnYAnimation;
        private static FrameworkElement _currentTiltElement;

        public Dictionary<string, object> Store { get; set; }

        protected override void OnPointerPressed(PointerRoutedEventArgs e)
        {
            base.OnPointerPressed(e);

            BeginTiltEffect(this);
        }

        protected override void OnPointerCaptureLost(PointerRoutedEventArgs e)
        {
            base.OnPointerCaptureLost(e);

            EndTiltEffect(this);
        }

        private static void OnPointerExited(object sender, PointerRoutedEventArgs e)
        {
            EndTiltEffect(sender as FrameworkElement);
        }

        static void BeginTiltEffect(FrameworkElement element)
        {
            if (_tiltReturnStoryboard != null)
            {
                StopTiltReturnStoryboardAndCleanup();
            }

            if (PrepareControlForTilt(element) == false)
            {
                return;
            }

            _currentTiltElement = element;
            PrepareTiltReturnStoryboard(element);

            ApplyTiltEffect(_currentTiltElement);
        }

        private static void ResetTiltReturnStoryboard()
        {
            _tiltReturnStoryboard.Stop();
        }

        private static void ApplyTiltEffect(FrameworkElement element)
        {
            ResetTiltReturnStoryboard();

            ScaleTransform transform = element.RenderTransform as ScaleTransform;
            transform.ScaleX = 0.96;
            transform.ScaleY = 0.96;
        }

        private static void EndTiltEffect(FrameworkElement element)
        {
            if (element != null)
            {
                element.PointerExited -= OnPointerExited;
            }

            if (_tiltReturnStoryboard != null)
            {
                if (_tiltReturnStoryboard.GetCurrentState() != ClockState.Active)
                {
                    _tiltReturnStoryboard.Begin();
                }
            }
            else
            {
                StopTiltReturnStoryboardAndCleanup();
            }
        }

        private static void StopTiltReturnStoryboardAndCleanup()
        {
            if (_tiltReturnStoryboard != null)
            {
                _tiltReturnStoryboard.Stop();
            }

            RevertPrepareControlForTilt(_currentTiltElement);
        }

        private static void RevertPrepareControlForTilt(FrameworkElement element)
        {
            element.PointerExited -= OnPointerExited;
            element.RenderTransform = null;
        }

        static bool PrepareControlForTilt(FrameworkElement element)
        {
            if (element.RenderTransform != null && element.RenderTransform.GetType() != typeof(MatrixTransform))
            {
                return false;
            }

            ScaleTransform transform = new ScaleTransform();
            transform.CenterX = element.ActualWidth / 2;
            transform.CenterY = element.ActualHeight / 2;
            transform.ScaleX = 1;
            transform.ScaleY = 1;
            element.RenderTransform = transform;

            element.PointerExited += OnPointerExited;

            return true;
        }

        static void PrepareTiltReturnStoryboard(FrameworkElement element)
        {
            if (_tiltReturnStoryboard == null)
            {
                _tiltReturnStoryboard = new Storyboard();
                _tiltReturnStoryboard.Completed += TiltReturnStoryboardCompleted;

                _tiltReturnXAnimation = new DoubleAnimation();
                Storyboard.SetTargetProperty(_tiltReturnXAnimation, "(ScaleTransform.ScaleX)");
                _tiltReturnXAnimation.BeginTime = TiltReturnAnimationDelay;
                _tiltReturnXAnimation.To = 1;
                _tiltReturnXAnimation.Duration = TiltReturnAnimationDuration;

                _tiltReturnYAnimation = new DoubleAnimation();
                Storyboard.SetTargetProperty(_tiltReturnYAnimation, "(ScaleTransform.ScaleY)");
                _tiltReturnYAnimation.BeginTime = TiltReturnAnimationDelay;
                _tiltReturnYAnimation.To = 1;
                _tiltReturnYAnimation.Duration = TiltReturnAnimationDuration;

                _tiltReturnStoryboard.Children.Add(_tiltReturnXAnimation);
                _tiltReturnStoryboard.Children.Add(_tiltReturnYAnimation);
            }

            Storyboard.SetTarget(_tiltReturnXAnimation, element.RenderTransform);
            Storyboard.SetTarget(_tiltReturnYAnimation, element.RenderTransform);
        }

        private static void TiltReturnStoryboardCompleted(object sender, object e)
        {
            ResetTiltEffect(_currentTiltElement);
        }

        private static void ResetTiltEffect(FrameworkElement element)
        {
            ScaleTransform transform = element.RenderTransform as ScaleTransform;
            transform.ScaleX = 1;
            transform.ScaleY = 1;
        }
    }
}
